package com.cj.controller;

import java.net.InetAddress;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.cj.util.RedisLock;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;


@Controller
public class ApiController {
	
	@Autowired
	RedisTemplate<String, String> redisTemplate;
	
	@Autowired
	RedisLock redisLock;
	
	@RequestMapping("/index")
	public String toIndex(Model model,HttpServletRequest request){
		Double current_stock = redisTemplate.opsForZSet().score("stock", "prod101");
		if(current_stock == null) {
			current_stock = 0D;
		}
		model.addAttribute("current_stock",current_stock.intValue());
		String today = DateUtil.today();
		String ip = getIpAddr(request);
		redisTemplate.opsForHyperLogLog().add(today, ip);
		Long size = redisTemplate.opsForHyperLogLog().size(today);
		System.out.println("目前"+today+"有"+size+"人登录");
		return "index";
	}
	
	@RequestMapping(value = "/stock/api",method = RequestMethod.POST)
	public String stockApi(Long id, Model model,Long delay) throws InterruptedException{
		String prodKey = "prod"+id;//// 拼凑成 prod101 这样的key
		while(redisLock.addLock(redisTemplate)) {
			Double current_stock = redisTemplate.opsForZSet().score("stock", prodKey);
			if(current_stock<=0) {
				model.addAttribute("current_stock", current_stock.intValue());//代表没库存
			}else{
				if(delay!=null && delay==1) { //这里开始模拟卡顿了。 假设你判断后，正好进来了很多并发  或者你卡顿了
					Thread.sleep(50000);//模拟卡顿2秒
				}
					double delta = -1;
					Double score = redisTemplate.opsForZSet().incrementScore("stock", prodKey, delta);
					
					model.addAttribute("current_stock", score.intValue());
			}
			redisTemplate.delete("lock");
			break;
		}
		
		
		return "index";
	}
	
	
	//使用事务
	@RequestMapping(value = "/stock/api2",method = RequestMethod.POST)
	public String stockApi2(Long id, Model model,Long delay) throws InterruptedException{
		String prodKey = "prod"+id;//// 拼凑成 prod101 这样的key
		String uuId = IdUtil.simpleUUID();//生成 一个随机唯一ID
		while(!redisLock.addLock(redisTemplate,uuId)) {
			Thread.sleep(2000);//休眠2秒
		}
		
		List<Object> results = redisTemplate.execute(new SessionCallback<List<Object>>() {
			public List<Object> execute(RedisOperations operations) throws DataAccessException{
				operations.watch("lock");//监听lock
				Double current_stock = operations.opsForZSet().score("stock", prodKey);//缓存里面取库存
				if(current_stock == null || current_stock<=0) {
					model.addAttribute("current_stock", current_stock.intValue());//代表没库存
					model.addAttribute("msg","no stock");
					operations.multi();
					operations.delete("lock");
					return operations.exec();
					
				}else { 
					if(delay!=null && delay==1){//这里开始模拟卡顿了。 假设你判断后，正好进来了很多并发  或者你卡顿了
						try {
							Thread.sleep(5000);//模拟卡顿5秒
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					operations.multi();
					double delta = -1;
					Double score = operations.opsForZSet().incrementScore("stock", prodKey, delta);//库存减1
					operations.delete("lock");
					return operations.exec();
				}	
			}
		});
		
		if(results!=null && results.size()>0) {
			return "index";
		}else {//代表没有执行
			Double current_stock = redisTemplate.opsForZSet().score("stock", prodKey);//缓存里面取库存
			model.addAttribute("current_stock", current_stock.intValue());//代表没库存
			model.addAttribute("msg","canceled");
			return "index";
		}
		
		
		
	}
	
	/** 
     * @Description: 获取客户端IP地址   
     */  
    private String getIpAddr(HttpServletRequest request) {   
           String ip = request.getHeader("x-forwarded-for");   
           if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {   
               ip = request.getHeader("Proxy-Client-IP");   
           }   
           if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {   
               ip = request.getHeader("WL-Proxy-Client-IP");   
           }   
           if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {   
               ip = request.getRemoteAddr();   
               if(ip.equals("127.0.0.1")){     
                   //根据网卡取本机配置的IP     
                   InetAddress inet=null;     
                   try {     
                       inet = InetAddress.getLocalHost();     
                   } catch (Exception e) {     
                       e.printStackTrace();     
                   }     
                   ip= inet.getHostAddress();     
               }  
           }   
           // 多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割  
           if(ip != null && ip.length() > 15){    
               if(ip.indexOf(",")>0){     
                   ip = ip.substring(0,ip.indexOf(","));     
               }     
           }     
           return ip;   
    }  
	
	

}
